﻿//
// XN4SL - Xna Framework for Silverlight.
//
using System;
using System.Windows.Media;
using System.Windows.Controls;
using System.IO;
using System.Xml;

namespace Xn4Sl.Framework.Media
{
    /// <summary>
    /// Provides methods and properties to play, pause, resume, and stop songs. also
    /// exposes shuffle, repeat, volume, play position, and visualization capabilities.
    /// </summary>
    public static class MediaPlayer
    {
        /// <summary>
        /// An audio engine for this MediaPlayer.
        /// </summary>
        public static MediaElement Content = new MediaElement() { Volume = 1, BufferingTime = new TimeSpan(0, 0, 60) };

        /// <summary>
        /// Initializes a MediaPlayer.
        /// </summary>
        static MediaPlayer()
        {
            Content.CurrentStateChanged += new System.Windows.RoutedEventHandler(mediaElement_CurrentStateChanged);
            Content.MediaEnded += new System.Windows.RoutedEventHandler(mediaElement_MediaEnded);
        }

        /// <summary>
        /// Occurs when the value of the CurrentState property changes. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void mediaElement_CurrentStateChanged(object sender, System.Windows.RoutedEventArgs e)
        {
            switch (Content.CurrentState)
            {
                case MediaElementState.AcquiringLicense:
                    break;
                case MediaElementState.Buffering:
                    break;
                case MediaElementState.Closed:
                    break;
                case MediaElementState.Individualizing:
                    break;
                case MediaElementState.Opening:
                    break;
                case MediaElementState.Paused:
                    break;
                case MediaElementState.Playing:
                    break;
                case MediaElementState.Stopped:
                    break;
                default:
                    break;
            }
            if (MediaStateChanged != null) MediaStateChanged(null, null);
        }

        /// <summary>
        /// Occurs when the MediaElement is no longer playing audio or video. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void mediaElement_MediaEnded(object sender, System.Windows.RoutedEventArgs e)
        {
            if (IsRepeating)
            {
                Content.Position = TimeSpan.Zero;
                Content.Play();
            }
        }

        /// <summary>
        /// Determines whether the game has control of the background music.
        /// </summary>
        public static bool GameHasControl
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Gets or set the muted setting for the media player.
        /// </summary>
        public static bool IsMuted 
        {
            get
            {
                return Content.IsMuted;
            }
            set
            {
                Content.IsMuted = value;
            }
        }

        /// <summary>
        /// Gets or sets the repeat setting for the media player.
        /// </summary>
        private static bool isRepeating;
        public static bool IsRepeating 
        {
            get
            {
                return isRepeating;
            }
            set
            {
                isRepeating = value;
            }
        }

        /// <summary>
        /// Gets or sets the shuffle setting for the media player.
        /// </summary>
        public static bool IsShuffled { get; set; }

        /// <summary>
        /// Gets or sets the visualization enabled setting for the media player.
        /// </summary>
        public static bool IsVisualizationEnabled { get; set; }

        /// <summary>
        /// Gets the play position within the currently playing song.
        /// </summary>
        public static TimeSpan PlayPosition
        {
            get
            {
                return Content.Position;
            }
        }

        /// <summary>
        /// Gets the media playback queue, MediaQueue.
        /// </summary>
        private static MediaQueue queue = new MediaQueue();
        public static MediaQueue Queue
        {
            get
            {
                return queue;
            }
        }

        /// <summary>
        /// Gets the media playback state, MediaState.
        /// </summary>
        public static MediaState State
        {
            get
            {
                switch (Content.CurrentState)
                {
                    case System.Windows.Media.MediaElementState.Paused:
                        return MediaState.Paused;
                    case System.Windows.Media.MediaElementState.Playing:
                        return MediaState.Playing;
                    case System.Windows.Media.MediaElementState.Stopped:
                        return MediaState.Stopped;
                    default:
                        return MediaState.Stopped;
                }
            }
        }

        /// <summary>
        /// Gets or sets the media player volume: from 0.0f (silence) 
        /// to 1.0f (full volume relative to the current device volume).
        /// </summary>
        public static float Volume 
        {
            get
            {
                return (float)Content.Volume;
            }
            set
            {
                Content.Volume = value;
            }
        }

        /// <summary>
        /// Raised when the active song changes due to active playback or due to explicit
        /// calls to the MediaPlayer.MoveNext or MediaPlayer.MovePrevious methods.
        /// </summary>
        public static event EventHandler ActiveSongChanged;

        /// <summary>
        /// Raised when the media player play state changes.
        /// </summary>
        public static event EventHandler MediaStateChanged;

        /// <summary>
        /// Retrieves visualization (frequency and sample) data for the currently-playing song. 
        /// </summary>
        /// <param name="visualizationData">Visualization (frequency and sample) data for the currently playing song.</param>
        public static void GetVisualizationData(VisualizationData visualizationData)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Moves to the next song in the queue of playing songs.
        /// </summary>
        public static void MoveNext()
        {
            if (queue.ActiveSongIndex == queue.Count - 1)
            {
                queue.ActiveSongIndex = 0;
            }
            else
            {
                queue.ActiveSongIndex++;
            }

            if (ActiveSongChanged != null) ActiveSongChanged(null, null);
        }

        /// <summary>
        /// Moves to the previous song in the queue of playing songs.
        /// </summary>
        public static void MovePrevious()
        {
            if (queue.ActiveSongIndex == 0)
            {
                queue.ActiveSongIndex = queue.Count - 1;
            }
            else
            {
                queue.ActiveSongIndex--;
            }

            if (ActiveSongChanged != null) ActiveSongChanged(null, null);
        }

        /// <summary>
        /// Pauses the currently playing song.
        /// </summary>
        public static void Pause()
        {
            Content.Pause();
        }

        /// <summary>
        /// Plays a Song.
        /// </summary>
        /// <param name="song">Song to play.</param>
        public static void Play(Song song)
        {
            queue.Add(song);

            //
            // Read an audio file.
            //
            Content.SetSource(ReadMediaFile(song.Name));
        }

        /// <summary>
        /// Reads a media file from XAP package.
        /// </summary>
        /// <param name="filename">Requested file name.</param>
        /// <returns>Audio stream.</returns>
        private static Stream ReadMediaFile(string filename)
        {
            // TODO: Use ContentManager.
            Stream stream = null;

            //
            // Find an asset in a XAP package.
            //
            try
            {
                XmlXapResolver xmlRes = new XmlXapResolver();
                stream = xmlRes.GetEntity(new Uri(filename, UriKind.Relative), null, null) as Stream;
            }
            catch 
            {
                throw new Exception(String.Format("Failed to load: {0}!", filename));
            }

            return stream;
        }

        /// <summary>
        /// Plays a SongCollection.
        /// </summary>
        /// <param name="songs">SongCollection to play.</param>
        public static void Play(SongCollection songs)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Plays a SongCollection, starting with the Song at the specified index.
        /// </summary>
        /// <param name="songs">SongCollection to play.</param>
        /// <param name="index">Index of the song in the collection at which playback should begin.</param>
        public static void Play(SongCollection songs, int index)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Resumes a paused song.
        /// </summary>
        public static void Resume()
        {
            Content.Play();
        }

        /// <summary>
        /// Stops playing a song.
        /// </summary>
        public static void Stop()
        {
            Content.Stop();
        }
    }
}
